/*
Designer   : Renyangang

Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at

	http://www.apache.org/licenses/LICENSE-2.0

Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/
package main

import (
	"context"
	"fmt"
	"fpga-vboard/config"
	"fpga-vboard/fpga"
	"fpga-vboard/logger"
	"fpga-vboard/pins"
	"fpga-vboard/soc"
	"fpga-vboard/standalone"
	"fpga-vboard/utils"
	"os"

	"github.com/wailsapp/wails/v2/pkg/runtime"
)

// App struct
type App struct {
	ctx context.Context
}

// NewApp creates a new App application struct
func NewApp() *App {
	return &App{}
}

// startup is called when the app starts. The context is saved
// so we can call the runtime methods
func (a *App) startup(ctx context.Context) {
	a.ctx = ctx
	logger.Logger.Ctx = ctx
	if config.CurAppParams.FirstPage == "uartterm" {
		standalone.StartSerialTerm(ctx)
	}
}

func (a *App) Run(config *soc.SocConfig) {
	soc.RunSoc(a.ctx, config)
}

func (a *App) Shutdown() {
	soc.StopSoc()
}

func (a *App) GetConfig() *soc.SocConfig {
	return soc.GetDefaultSocConfig()
}

func (a *App) GetFileContent(options runtime.OpenDialogOptions) string {
	filePath, err := runtime.OpenFileDialog(a.ctx, options)
	if err != nil {
		logger.FatalEvent("Error opening file failed. %v", err)
		return ""
	}
	fileContent, err := os.ReadFile(filePath)
	if err != nil {
		logger.FatalEvent("Error reading file failed. %v", err)
		return ""
	}
	return string(fileContent)
}

func (a *App) GetFile(options runtime.OpenDialogOptions) string {
	path, err := runtime.OpenFileDialog(a.ctx, options)
	if err != nil {
		logger.FatalEvent("Error opening file failed. %v", err)
		return ""
	}
	return path
}

func (a *App) GetDir(options runtime.OpenDialogOptions) string {
	path, err := runtime.OpenDirectoryDialog(a.ctx, options)
	if err != nil {
		logger.FatalEvent("Error opening dir failed. %v", err)
		return ""
	}
	return path
}

func (a *App) SaveFile(content string, options runtime.SaveDialogOptions) bool {
	filePath, err := runtime.SaveFileDialog(a.ctx, options)
	if err != nil {
		logger.FatalEvent("Error saving file failed. %v", err)
		return false
	}
	err = os.WriteFile(filePath, []byte(content), 0644)
	if err != nil {
		logger.FatalEvent("Error writing file failed. %v", err)
		return false
	}
	return true
}

func (a *App) SaveDefaultConfigFile(content string) bool {
	err := os.WriteFile(config.AppCfg.DefaultConfigPath, []byte(content), 0644)
	if err != nil {
		logger.FatalEvent("Error writing file failed. %v", err)
		return false
	}
	return true
}

func (a *App) LoadDefaultConfigFile() string {
	contentbs, err := os.ReadFile(config.AppCfg.DefaultConfigPath)
	if err != nil {
		logger.FatalEvent("Error reading file failed. %v", err)
		return ""
	}
	return string(contentbs)
}

func (a *App) GetPageConfig() *config.AppParams {
	return config.CurAppParams
}

func (a *App) MakeVerilatorLib(config *fpga.VerilatorConfig) *fpga.SynthesisResult {
	utils.SetCtx(a.ctx)
	logger.InfoLog("Making verilator lib: %v", config)
	synthRes, err := fpga.DoSynthesis(&fpga.SynthesisConfig{
		SrcType:   fpga.SrcTypeVerilator,
		ExtraArgs: config,
	})
	if err != nil {
		logger.FatalEvent("Error making verilator lib failed. %v", err)
		return nil
	}
	runtime.EventsEmit(a.ctx, "cmdoutput", &logger.LogEventMsg{
		Msgtype: logger.MsgTypeSuccess,
		Msg:     "verilator lib generated successfully",
	})
	return synthRes
}

func (a *App) RunCmd(cmd string) {
	utils.RunCmdInCurDirBackground(cmd)
}

// just for generate the pins namespace for frontend typescript
func (a *App) ForPinDef() (*pins.PinDef, *pins.PinMap) {
	m := &pins.PinMap{}
	m.InputPinName = "in"
	m.OutputPinName = "out"
	fmt.Println(m)
	return pins.NewPinDef("sdfds", 3, pins.PinDirectionInout), m
}
